{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 第5阶段_第1讲_可视化原则与图表选择\n",
    "\n",
    "## 学习目标\n",
    "1. 理解数据可视化的核心原则和最佳实践\n",
    "2. 掌握不同类型图表的适用场景\n",
    "3. 熟练使用Matplotlib创建基础图表\n",
    "4. 掌握Seaborn高级可视化技巧\n",
    "5. 学会图表美化和定制化\n",
    "6. 能够根据数据特征选择合适的可视化方式\n",
    "\n",
    "## 为什么需要数据可视化?\n",
    "\n",
    "数据可视化是数据分析的重要环节:\n",
    "- 📊 **快速理解数据**: 一图胜千言,瞬间看出数据规律\n",
    "- 🎯 **发现异常**: 通过可视化快速识别异常值和离群点\n",
    "- 💡 **洞察挖掘**: 图表能揭示数据背后的故事\n",
    "- 🗣️ **有效沟通**: 向决策者展示分析结果的最佳方式\n",
    "- ✅ **验证假设**: 通过可视化验证分析假设是否成立\n",
    "\n",
    "## Excel vs Python可视化\n",
    "\n",
    "| 功能 | Excel | Python (Matplotlib/Seaborn) |\n",
    "|------|-------|-----------------------------|\n",
    "| 基础图表 | 插入图表,点击式 | 代码绘制,可重复 |\n",
    "| 图表类型 | 10+种常用图表 | 50+种图表类型 |\n",
    "| 定制化 | 有限(样式/颜色) | 完全定制(像素级) |\n",
    "| 批量生成 | 手动重复 | 循环自动化 |\n",
    "| 交互性 | 有限 | 丰富(Plotly) |\n",
    "| 适用场景 | 小数据,快速展示 | 大数据,自动化,复杂图表 |\n",
    "| 学习曲线 | 低 | 中等 |\n",
    "| 可重复性 | 低 | 高(代码可复用) |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 导入必要的库\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "from matplotlib import rcParams\n",
    "import warnings\n",
    "warnings.filterwarnings('ignore')\n",
    "\n",
    "# 设置中文显示\n",
    "plt.rcParams['font.sans-serif'] = ['Arial Unicode MS', 'SimHei', 'STHeiti']\n",
    "plt.rcParams['axes.unicode_minus'] = False\n",
    "\n",
    "# 设置默认图表样式\n",
    "plt.style.use('seaborn-v0_8-darkgrid')\n",
    "sns.set_palette('husl')\n",
    "\n",
    "# 设置图表质量\n",
    "plt.rcParams['figure.dpi'] = 100\n",
    "plt.rcParams['savefig.dpi'] = 300\n",
    "\n",
    "# 设置随机种子\n",
    "np.random.seed(42)\n",
    "\n",
    "print(\"=\"*100)\n",
    "print(\"🎨 数据可视化原则与图表选择\")\n",
    "print(\"=\"*100)\n",
    "print(\"\\n✅ 环境配置完成!\")\n",
    "print(f\"Matplotlib版本: {plt.matplotlib.__version__}\")\n",
    "print(f\"Seaborn版本: {sns.__version__}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 一、数据可视化的核心原则\n",
    "\n",
    "### 1.1 数据可视化六大原则\n",
    "\n",
    "#### 原则1:简洁性(Simplicity)\n",
    "- **less is more**: 去掉不必要的元素\n",
    "- 避免3D图表、过多装饰\n",
    "- 一图一主题\n",
    "\n",
    "#### 原则2:准确性(Accuracy)\n",
    "- 不歪曲数据真相\n",
    "- Y轴从0开始(大多数情况)\n",
    "- 避免误导性比例\n",
    "\n",
    "#### 原则3:清晰性(Clarity)\n",
    "- 清晰的标题和标签\n",
    "- 合适的字号\n",
    "- 图例位置合理\n",
    "\n",
    "#### 原则4:一致性(Consistency)\n",
    "- 统一的配色方案\n",
    "- 统一的图表风格\n",
    "- 统一的单位格式\n",
    "\n",
    "#### 原则5:聚焦性(Focus)\n",
    "- 突出关键信息\n",
    "- 使用颜色/粗细/标注引导视线\n",
    "- 弱化次要信息\n",
    "\n",
    "#### 原则6:美观性(Aesthetics)\n",
    "- 协调的配色\n",
    "- 合理的留白\n",
    "- 专业的排版"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2 图表选择决策树\n",
    "\n",
    "```\n",
    "你想展示什么?\n",
    "│\n",
    "├─ 比较 (Comparison)\n",
    "│   ├─ 类别间比较 → 柱状图(Bar Chart)\n",
    "│   ├─ 时间序列比较 → 折线图(Line Chart)\n",
    "│   └─ 多维比较 → 分组柱状图/热力图\n",
    "│\n",
    "├─ 分布 (Distribution)\n",
    "│   ├─ 单变量分布 → 直方图(Histogram)\n",
    "│   ├─ 多组分布对比 → 箱线图(Box Plot)\n",
    "│   └─ 密度分布 → 小提琴图(Violin Plot)/KDE\n",
    "│\n",
    "├─ 组成 (Composition)\n",
    "│   ├─ 静态占比 → 饼图(Pie Chart)/环形图\n",
    "│   ├─ 时间变化占比 → 堆叠面积图\n",
    "│   └─ 层级结构 → 树状图(Treemap)\n",
    "│\n",
    "├─ 关系 (Relationship)\n",
    "│   ├─ 两变量关系 → 散点图(Scatter Plot)\n",
    "│   ├─ 三变量关系 → 气泡图(Bubble Chart)\n",
    "│   └─ 相关性 → 热力图(Heatmap)\n",
    "│\n",
    "└─ 趋势 (Trend)\n",
    "    ├─ 时间趋势 → 折线图(Line Chart)\n",
    "    ├─ 多序列趋势 → 多折线图\n",
    "    └─ 趋势分解 → 面积图(Area Chart)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 二、Matplotlib基础\n",
    "\n",
    "### 2.1 Matplotlib架构\n",
    "\n",
    "```\n",
    "Figure (画布)\n",
    "  └─ Axes (坐标系)\n",
    "      ├─ Title (标题)\n",
    "      ├─ X-axis (X轴)\n",
    "      ├─ Y-axis (Y轴)\n",
    "      ├─ Legend (图例)\n",
    "      └─ Plots (图形元素)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 演示Matplotlib的两种绘图方式\n",
    "\n",
    "# 生成示例数据\n",
    "x = np.linspace(0, 10, 100)\n",
    "y1 = np.sin(x)\n",
    "y2 = np.cos(x)\n",
    "\n",
    "print(\"=\"*100)\n",
    "print(\"📊 Matplotlib两种绘图风格\")\n",
    "print(\"=\"*100)\n",
    "\n",
    "# 方式1: pyplot风格(类似MATLAB,适合快速绘图)\n",
    "print(\"\\n【方式1: pyplot风格(快速绘图)】\")\n",
    "plt.figure(figsize=(10, 4))\n",
    "plt.plot(x, y1, label='sin(x)')\n",
    "plt.plot(x, y2, label='cos(x)')\n",
    "plt.title('Pyplot风格示例')\n",
    "plt.xlabel('X轴')\n",
    "plt.ylabel('Y轴')\n",
    "plt.legend()\n",
    "plt.grid(True, alpha=0.3)\n",
    "plt.show()\n",
    "\n",
    "# 方式2: 面向对象风格(推荐,更灵活)\n",
    "print(\"\\n【方式2: 面向对象风格(推荐使用)】\")\n",
    "fig, ax = plt.subplots(figsize=(10, 4))\n",
    "ax.plot(x, y1, label='sin(x)', linewidth=2)\n",
    "ax.plot(x, y2, label='cos(x)', linewidth=2)\n",
    "ax.set_title('面向对象风格示例', fontsize=14, fontweight='bold')\n",
    "ax.set_xlabel('X轴', fontsize=12)\n",
    "ax.set_ylabel('Y轴', fontsize=12)\n",
    "ax.legend(fontsize=10)\n",
    "ax.grid(True, alpha=0.3)\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "print(\"\\n💡 说明:\")\n",
    "print(\"  - pyplot风格: 适合交互式快速绘图\")\n",
    "print(\"  - 面向对象风格: 适合复杂图表和子图布局,推荐使用\")\n",
    "print(\"  - 本课程主要使用面向对象风格\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2 创建图表的基本步骤"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 完整的图表创建流程\n",
    "print(\"\\n\" + \"=\"*100)\n",
    "print(\"📝 完整的图表创建流程\")\n",
    "print(\"=\"*100)\n",
    "\n",
    "# 第1步: 准备数据\n",
    "months = ['1月', '2月', '3月', '4月', '5月', '6月']\n",
    "sales = [120, 135, 142, 158, 165, 180]\n",
    "costs = [80, 85, 88, 95, 98, 105]\n",
    "\n",
    "# 第2步: 创建画布和坐标系\n",
    "fig, ax = plt.subplots(figsize=(12, 6))  # figsize=(宽, 高),单位为英寸\n",
    "\n",
    "# 第3步: 绘制图形\n",
    "ax.plot(months, sales, marker='o', linewidth=2.5, markersize=8, label='销售额', color='#2E86AB')\n",
    "ax.plot(months, costs, marker='s', linewidth=2.5, markersize=8, label='成本', color='#A23B72')\n",
    "\n",
    "# 第4步: 添加标题和标签\n",
    "ax.set_title('2024年上半年销售与成本趋势', fontsize=16, fontweight='bold', pad=20)\n",
    "ax.set_xlabel('月份', fontsize=13, fontweight='bold')\n",
    "ax.set_ylabel('金额(万元)', fontsize=13, fontweight='bold')\n",
    "\n",
    "# 第5步: 添加图例\n",
    "ax.legend(fontsize=11, loc='upper left', frameon=True, shadow=True)\n",
    "\n",
    "# 第6步: 添加网格\n",
    "ax.grid(True, linestyle='--', alpha=0.4, color='gray')\n",
    "\n",
    "# 第7步: 设置坐标轴范围和刻度\n",
    "ax.set_ylim([0, 200])\n",
    "ax.yaxis.set_major_locator(plt.MultipleLocator(20))  # Y轴主刻度间隔20\n",
    "\n",
    "# 第8步: 添加数据标签\n",
    "for i, (m, s, c) in enumerate(zip(months, sales, costs)):\n",
    "    ax.text(i, s + 3, f'{s}', ha='center', va='bottom', fontsize=9, color='#2E86AB')\n",
    "    ax.text(i, c - 3, f'{c}', ha='center', va='top', fontsize=9, color='#A23B72')\n",
    "\n",
    "# 第9步: 美化(去除顶部和右侧边框)\n",
    "ax.spines['top'].set_visible(False)\n",
    "ax.spines['right'].set_visible(False)\n",
    "\n",
    "# 第10步: 调整布局并显示\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "print(\"\\n✅ 完整图表创建完成!\")\n",
    "print(\"\\n💡 关键技巧:\")\n",
    "print(\"  1. figsize控制图表大小\")\n",
    "print(\"  2. marker设置数据点标记样式\")\n",
    "print(\"  3. label用于图例显示\")\n",
    "print(\"  4. fontsize/fontweight控制字体\")\n",
    "print(\"  5. grid添加网格线\")\n",
    "print(\"  6. text添加数据标签\")\n",
    "print(\"  7. spines美化边框\")\n",
    "print(\"  8. tight_layout()自动调整布局\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 三、常用图表类型详解\n",
    "\n",
    "### 3.1 对比类图表\n",
    "\n",
    "#### 3.1.1 柱状图(Bar Chart) - 类别间对比"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 生成示例数据:各地区销售额\n",
    "regions = ['华东', '华南', '华北', '西南', '东北']\n",
    "region_sales = [280, 245, 215, 180, 120]\n",
    "\n",
    "print(\"=\"*100)\n",
    "print(\"📊 柱状图(Bar Chart) - 适用于类别间对比\")\n",
    "print(\"=\"*100)\n",
    "\n",
    "fig, axes = plt.subplots(2, 2, figsize=(15, 12))\n",
    "\n",
    "# 1. 基础柱状图\n",
    "axes[0, 0].bar(regions, region_sales, color='steelblue', alpha=0.8, edgecolor='black')\n",
    "axes[0, 0].set_title('基础柱状图', fontsize=13, fontweight='bold')\n",
    "axes[0, 0].set_ylabel('销售额(万元)', fontsize=11)\n",
    "axes[0, 0].grid(axis='y', alpha=0.3)\n",
    "# 添加数值标签\n",
    "for i, v in enumerate(region_sales):\n",
    "    axes[0, 0].text(i, v + 5, str(v), ha='center', va='bottom', fontsize=10, fontweight='bold')\n",
    "\n",
    "# 2. 水平柱状图\n",
    "axes[0, 1].barh(regions, region_sales, color='coral', alpha=0.8, edgecolor='black')\n",
    "axes[0, 1].set_title('水平柱状图(适合长标签)', fontsize=13, fontweight='bold')\n",
    "axes[0, 1].set_xlabel('销售额(万元)', fontsize=11)\n",
    "axes[0, 1].grid(axis='x', alpha=0.3)\n",
    "# 添加数值标签\n",
    "for i, v in enumerate(region_sales):\n",
    "    axes[0, 1].text(v + 5, i, str(v), ha='left', va='center', fontsize=10, fontweight='bold')\n",
    "\n",
    "# 3. 分组柱状图\n",
    "x = np.arange(len(regions))\n",
    "width = 0.35\n",
    "sales_2023 = region_sales\n",
    "sales_2024 = [s * 1.15 for s in region_sales]  # 增长15%\n",
    "\n",
    "axes[1, 0].bar(x - width/2, sales_2023, width, label='2023年', color='skyblue', alpha=0.8, edgecolor='black')\n",
    "axes[1, 0].bar(x + width/2, sales_2024, width, label='2024年', color='lightgreen', alpha=0.8, edgecolor='black')\n",
    "axes[1, 0].set_title('分组柱状图(多年对比)', fontsize=13, fontweight='bold')\n",
    "axes[1, 0].set_ylabel('销售额(万元)', fontsize=11)\n",
    "axes[1, 0].set_xticks(x)\n",
    "axes[1, 0].set_xticklabels(regions)\n",
    "axes[1, 0].legend(fontsize=10)\n",
    "axes[1, 0].grid(axis='y', alpha=0.3)\n",
    "\n",
    "# 4. 堆叠柱状图\n",
    "online_sales = [s * 0.6 for s in region_sales]\n",
    "offline_sales = [s * 0.4 for s in region_sales]\n",
    "\n",
    "axes[1, 1].bar(regions, online_sales, label='线上销售', color='#FF6B6B', alpha=0.8, edgecolor='black')\n",
    "axes[1, 1].bar(regions, offline_sales, bottom=online_sales, label='线下销售', color='#4ECDC4', alpha=0.8, edgecolor='black')\n",
    "axes[1, 1].set_title('堆叠柱状图(显示组成)', fontsize=13, fontweight='bold')\n",
    "axes[1, 1].set_ylabel('销售额(万元)', fontsize=11)\n",
    "axes[1, 1].legend(fontsize=10)\n",
    "axes[1, 1].grid(axis='y', alpha=0.3)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "print(\"\\n📝 柱状图使用场景:\")\n",
    "print(\"  ✓ 比较不同类别的数值\")\n",
    "print(\"  ✓ 展示排名\")\n",
    "print(\"  ✓ 时间维度的离散对比(如年度对比)\")\n",
    "print(\"  ✓ 展示构成(堆叠柱状图)\")\n",
    "print(\"\\n⚠️ 注意事项:\")\n",
    "print(\"  - 类别不宜过多(建议<15个)\")\n",
    "print(\"  - Y轴通常从0开始\")\n",
    "print(\"  - 柱子宽度和间距要适中\")\n",
    "print(\"  - 可以按数值大小排序,更直观\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.1.2 折线图(Line Chart) - 趋势变化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 生成时间序列数据\n",
    "dates = pd.date_range('2024-01-01', periods=180, freq='D')\n",
    "np.random.seed(42)\n",
    "base_value = 100\n",
    "trend = np.linspace(0, 30, 180)  # 上升趋势\n",
    "seasonal = 10 * np.sin(np.linspace(0, 4*np.pi, 180))  # 季节性波动\n",
    "noise = np.random.normal(0, 3, 180)  # 随机噪声\n",
    "values = base_value + trend + seasonal + noise\n",
    "\n",
    "print(\"\\n\" + \"=\"*100)\n",
    "print(\"📈 折线图(Line Chart) - 适用于趋势分析\")\n",
    "print(\"=\"*100)\n",
    "\n",
    "fig, axes = plt.subplots(2, 2, figsize=(16, 12))\n",
    "\n",
    "# 1. 基础折线图\n",
    "axes[0, 0].plot(dates, values, linewidth=2, color='#2E86AB')\n",
    "axes[0, 0].set_title('基础折线图(单序列)', fontsize=13, fontweight='bold')\n",
    "axes[0, 0].set_xlabel('日期', fontsize=11)\n",
    "axes[0, 0].set_ylabel('数值', fontsize=11)\n",
    "axes[0, 0].grid(True, alpha=0.3)\n",
    "axes[0, 0].tick_params(axis='x', rotation=45)\n",
    "\n",
    "# 2. 多折线图对比\n",
    "product_a = values\n",
    "product_b = values * 0.8 + np.random.normal(0, 2, 180)\n",
    "product_c = values * 1.2 + np.random.normal(0, 2, 180)\n",
    "\n",
    "axes[0, 1].plot(dates, product_a, linewidth=2, label='产品A', color='#FF6B6B')\n",
    "axes[0, 1].plot(dates, product_b, linewidth=2, label='产品B', color='#4ECDC4')\n",
    "axes[0, 1].plot(dates, product_c, linewidth=2, label='产品C', color='#45B7D1')\n",
    "axes[0, 1].set_title('多折线图(多产品对比)', fontsize=13, fontweight='bold')\n",
    "axes[0, 1].set_xlabel('日期', fontsize=11)\n",
    "axes[0, 1].set_ylabel('销量', fontsize=11)\n",
    "axes[0, 1].legend(fontsize=10, loc='upper left')\n",
    "axes[0, 1].grid(True, alpha=0.3)\n",
    "axes[0, 1].tick_params(axis='x', rotation=45)\n",
    "\n",
    "# 3. 带标记点的折线图\n",
    "monthly_dates = pd.date_range('2024-01', periods=6, freq='M')\n",
    "monthly_values = [120, 135, 142, 158, 165, 180]\n",
    "\n",
    "axes[1, 0].plot(monthly_dates, monthly_values, marker='o', markersize=10, linewidth=2.5,\n",
    "                color='#A23B72', markerfacecolor='white', markeredgewidth=2)\n",
    "axes[1, 0].set_title('带标记的折线图', fontsize=13, fontweight='bold')\n",
    "axes[1, 0].set_xlabel('月份', fontsize=11)\n",
    "axes[1, 0].set_ylabel('销售额(万元)', fontsize=11)\n",
    "axes[1, 0].grid(True, alpha=0.3)\n",
    "# 添加数值标签\n",
    "for date, val in zip(monthly_dates, monthly_values):\n",
    "    axes[1, 0].text(date, val + 3, f'{val}', ha='center', fontsize=10, fontweight='bold')\n",
    "\n",
    "# 4. 面积图(Area Chart)\n",
    "axes[1, 1].fill_between(dates, values, alpha=0.4, color='#95E1D3', label='销售额')\n",
    "axes[1, 1].plot(dates, values, linewidth=2, color='#38ADA9', label='趋势线')\n",
    "axes[1, 1].axhline(y=values.mean(), color='red', linestyle='--', linewidth=2, label=f'平均值={values.mean():.1f}')\n",
    "axes[1, 1].set_title('面积图(强调数量)', fontsize=13, fontweight='bold')\n",
    "axes[1, 1].set_xlabel('日期', fontsize=11)\n",
    "axes[1, 1].set_ylabel('数值', fontsize=11)\n",
    "axes[1, 1].legend(fontsize=10)\n",
    "axes[1, 1].grid(True, alpha=0.3)\n",
    "axes[1, 1].tick_params(axis='x', rotation=45)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "print(\"\\n📝 折线图使用场景:\")\n",
    "print(\"  ✓ 时间序列数据展示\")\n",
    "print(\"  ✓ 趋势分析\")\n",
    "print(\"  ✓ 连续变化的数据\")\n",
    "print(\"  ✓ 多个序列的对比\")\n",
    "print(\"\\n⚠️ 注意事项:\")\n",
    "print(\"  - 数据点过多时不要加标记(会很乱)\")\n",
    "print(\"  - 多折线时注意区分(颜色/线型)\")\n",
    "print(\"  - 不超过5条线(太多会混乱)\")\n",
    "print(\"  - X轴通常是时间或有序变量\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2 分布类图表\n",
    "\n",
    "#### 3.2.1 直方图(Histogram) - 数值分布"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 生成不同分布的数据\n",
    "np.random.seed(42)\n",
    "normal_data = np.random.normal(100, 15, 1000)  # 正态分布\n",
    "skewed_data = np.random.gamma(2, 20, 1000) + 50  # 右偏分布\n",
    "\n",
    "print(\"\\n\" + \"=\"*100)\n",
    "print(\"📊 直方图(Histogram) - 显示数值分布\")\n",
    "print(\"=\"*100)\n",
    "\n",
    "fig, axes = plt.subplots(2, 2, figsize=(15, 12))\n",
    "\n",
    "# 1. 基础直方图\n",
    "axes[0, 0].hist(normal_data, bins=30, color='steelblue', alpha=0.7, edgecolor='black')\n",
    "axes[0, 0].axvline(normal_data.mean(), color='red', linestyle='--', linewidth=2, label=f'均值={normal_data.mean():.1f}')\n",
    "axes[0, 0].axvline(np.median(normal_data), color='green', linestyle='--', linewidth=2, label=f'中位数={np.median(normal_data):.1f}')\n",
    "axes[0, 0].set_title('基础直方图(正态分布)', fontsize=13, fontweight='bold')\n",
    "axes[0, 0].set_xlabel('数值', fontsize=11)\n",
    "axes[0, 0].set_ylabel('频数', fontsize=11)\n",
    "axes[0, 0].legend(fontsize=10)\n",
    "axes[0, 0].grid(axis='y', alpha=0.3)\n",
    "\n",
    "# 2. 概率密度直方图\n",
    "axes[0, 1].hist(normal_data, bins=30, density=True, color='coral', alpha=0.7, edgecolor='black', label='频率分布')\n",
    "# 叠加KDE曲线\n",
    "from scipy.stats import gaussian_kde\n",
    "kde = gaussian_kde(normal_data)\n",
    "x_range = np.linspace(normal_data.min(), normal_data.max(), 100)\n",
    "axes[0, 1].plot(x_range, kde(x_range), 'r-', linewidth=2, label='KDE曲线')\n",
    "axes[0, 1].set_title('密度直方图 + KDE曲线', fontsize=13, fontweight='bold')\n",
    "axes[0, 1].set_xlabel('数值', fontsize=11)\n",
    "axes[0, 1].set_ylabel('密度', fontsize=11)\n",
    "axes[0, 1].legend(fontsize=10)\n",
    "axes[0, 1].grid(axis='y', alpha=0.3)\n",
    "\n",
    "# 3. 多组直方图对比(重叠)\n",
    "axes[1, 0].hist(normal_data, bins=30, alpha=0.5, color='blue', label='正态分布', edgecolor='black')\n",
    "axes[1, 0].hist(skewed_data, bins=30, alpha=0.5, color='red', label='右偏分布', edgecolor='black')\n",
    "axes[1, 0].set_title('多组直方图对比(重叠)', fontsize=13, fontweight='bold')\n",
    "axes[1, 0].set_xlabel('数值', fontsize=11)\n",
    "axes[1, 0].set_ylabel('频数', fontsize=11)\n",
    "axes[1, 0].legend(fontsize=10)\n",
    "axes[1, 0].grid(axis='y', alpha=0.3)\n",
    "\n",
    "# 4. 堆叠直方图\n",
    "group1 = np.random.normal(100, 10, 500)\n",
    "group2 = np.random.normal(110, 10, 500)\n",
    "axes[1, 1].hist([group1, group2], bins=20, stacked=True, color=['skyblue', 'lightcoral'], \n",
    "                alpha=0.8, edgecolor='black', label=['组1', '组2'])\n",
    "axes[1, 1].set_title('堆叠直方图', fontsize=13, fontweight='bold')\n",
    "axes[1, 1].set_xlabel('数值', fontsize=11)\n",
    "axes[1, 1].set_ylabel('频数', fontsize=11)\n",
    "axes[1, 1].legend(fontsize=10)\n",
    "axes[1, 1].grid(axis='y', alpha=0.3)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "print(\"\\n📝 直方图使用场景:\")\n",
    "print(\"  ✓ 了解数据分布形态\")\n",
    "print(\"  ✓ 发现异常值\")\n",
    "print(\"  ✓ 判断数据集中趋势和离散程度\")\n",
    "print(\"  ✓ 检验数据是否符合某种分布\")\n",
    "print(\"\\n⚠️ 注意事项:\")\n",
    "print(\"  - bins数量影响展示效果(一般20-50)\")\n",
    "print(\"  - 数据量较少时(<100)直方图效果不佳\")\n",
    "print(\"  - 可以用Sturges规则确定bins: bins = log2(n) + 1\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.2.2 箱线图(Box Plot) - 分布对比"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 生成多组数据\n",
    "np.random.seed(42)\n",
    "data_groups = [\n",
    "    np.random.normal(100, 15, 200),\n",
    "    np.random.normal(110, 20, 200),\n",
    "    np.random.normal(95, 10, 200),\n",
    "    np.random.normal(105, 25, 200)\n",
    "]\n",
    "labels = ['产品A', '产品B', '产品C', '产品D']\n",
    "\n",
    "print(\"\\n\" + \"=\"*100)\n",
    "print(\"📦 箱线图(Box Plot) - 多组分布对比\")\n",
    "print(\"=\"*100)\n",
    "\n",
    "fig, axes = plt.subplots(2, 2, figsize=(15, 12))\n",
    "\n",
    "# 1. 基础箱线图\n",
    "bp1 = axes[0, 0].boxplot(data_groups, labels=labels, patch_artist=True,\n",
    "                          boxprops=dict(facecolor='lightblue', alpha=0.7),\n",
    "                          medianprops=dict(color='red', linewidth=2),\n",
    "                          whiskerprops=dict(color='blue', linewidth=1.5),\n",
    "                          capprops=dict(color='blue', linewidth=1.5),\n",
    "                          flierprops=dict(marker='o', markerfacecolor='red', markersize=5, alpha=0.5))\n",
    "axes[0, 0].set_title('基础箱线图', fontsize=13, fontweight='bold')\n",
    "axes[0, 0].set_ylabel('数值', fontsize=11)\n",
    "axes[0, 0].grid(axis='y', alpha=0.3)\n",
    "\n",
    "# 添加图例说明\n",
    "from matplotlib.patches import Patch\n",
    "legend_elements = [\n",
    "    Patch(facecolor='lightblue', label='IQR(Q1-Q3)'),\n",
    "    plt.Line2D([0], [0], color='red', linewidth=2, label='中位数'),\n",
    "    plt.Line2D([0], [0], color='blue', linewidth=1.5, label='须(1.5×IQR)'),\n",
    "    plt.Line2D([0], [0], marker='o', color='w', markerfacecolor='red', markersize=5, label='异常值')\n",
    "]\n",
    "axes[0, 0].legend(handles=legend_elements, fontsize=9, loc='upper left')\n",
    "\n",
    "# 2. 水平箱线图\n",
    "bp2 = axes[0, 1].boxplot(data_groups, labels=labels, vert=False, patch_artist=True,\n",
    "                          boxprops=dict(facecolor='lightgreen', alpha=0.7),\n",
    "                          medianprops=dict(color='darkgreen', linewidth=2))\n",
    "axes[0, 1].set_title('水平箱线图', fontsize=13, fontweight='bold')\n",
    "axes[0, 1].set_xlabel('数值', fontsize=11)\n",
    "axes[0, 1].grid(axis='x', alpha=0.3)\n",
    "\n",
    "# 3. 带缺口的箱线图(显示置信区间)\n",
    "bp3 = axes[1, 0].boxplot(data_groups, labels=labels, notch=True, patch_artist=True,\n",
    "                          boxprops=dict(facecolor='coral', alpha=0.7),\n",
    "                          medianprops=dict(color='darkred', linewidth=2))\n",
    "axes[1, 0].set_title('带缺口箱线图(95%置信区间)', fontsize=13, fontweight='bold')\n",
    "axes[1, 0].set_ylabel('数值', fontsize=11)\n",
    "axes[1, 0].grid(axis='y', alpha=0.3)\n",
    "\n",
    "# 4. 箱线图 + 散点图\n",
    "bp4 = axes[1, 1].boxplot(data_groups, labels=labels, patch_artist=True, widths=0.5,\n",
    "                          boxprops=dict(facecolor='lightyellow', alpha=0.7),\n",
    "                          medianprops=dict(color='orange', linewidth=2))\n",
    "# 叠加散点\n",
    "for i, data in enumerate(data_groups):\n",
    "    x = np.random.normal(i+1, 0.04, len(data))  # 添加随机抖动\n",
    "    axes[1, 1].scatter(x, data, alpha=0.3, s=20)\n",
    "axes[1, 1].set_title('箱线图 + 散点图', fontsize=13, fontweight='bold')\n",
    "axes[1, 1].set_ylabel('数值', fontsize=11)\n",
    "axes[1, 1].grid(axis='y', alpha=0.3)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "print(\"\\n📝 箱线图构成:\")\n",
    "print(\"  - 箱体: Q1(25%分位数)到Q3(75%分位数),即IQR\")\n",
    "print(\"  - 中线: 中位数(Q2, 50%分位数)\")\n",
    "print(\"  - 须: 1.5×IQR范围内的最大/最小值\")\n",
    "print(\"  - 异常点: 超出须范围的点\")\n",
    "print(\"\\n📝 箱线图使用场景:\")\n",
    "print(\"  ✓ 多组数据分布对比\")\n",
    "print(\"  ✓ 快速识别异常值\")\n",
    "print(\"  ✓ 比较数据集中趋势和离散程度\")\n",
    "print(\"  ✓ 评估数据对称性\")\n",
    "print(\"\\n⚠️ 注意事项:\")\n",
    "print(\"  - 不显示数据的具体分布形态(如双峰)\")\n",
    "print(\"  - 适合样本量较大(>20)的情况\")\n",
    "print(\"  - 组数不宜过多(<10组为宜)\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.3 组成类图表\n",
    "\n",
    "#### 3.3.1 饼图(Pie Chart) - 占比关系"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 市场份额数据\n",
    "products = ['产品A', '产品B', '产品C', '产品D', '产品E', '其他']\n",
    "market_share = [28, 22, 18, 15, 10, 7]\n",
    "colors_pie = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8', '#CCCCCC']\n",
    "\n",
    "print(\"\\n\" + \"=\"*100)\n",
    "print(\"🥧 饼图(Pie Chart) - 显示占比关系\")\n",
    "print(\"=\"*100)\n",
    "\n",
    "fig, axes = plt.subplots(2, 2, figsize=(15, 12))\n",
    "\n",
    "# 1. 基础饼图\n",
    "axes[0, 0].pie(market_share, labels=products, autopct='%1.1f%%', colors=colors_pie,\n",
    "               startangle=90, textprops={'fontsize': 10})\n",
    "axes[0, 0].set_title('基础饼图', fontsize=13, fontweight='bold')\n",
    "\n",
    "# 2. 突出某个扇区(explode)\n",
    "explode = [0.1, 0, 0, 0, 0, 0]  # 突出第一个扇区\n",
    "axes[0, 1].pie(market_share, labels=products, autopct='%1.1f%%', colors=colors_pie,\n",
    "               explode=explode, startangle=90, shadow=True, textprops={'fontsize': 10})\n",
    "axes[0, 1].set_title('突出扇区饼图', fontsize=13, fontweight='bold')\n",
    "\n",
    "# 3. 环形图(Donut Chart)\n",
    "wedges, texts, autotexts = axes[1, 0].pie(market_share, labels=products, autopct='%1.1f%%',\n",
    "                                            colors=colors_pie, startangle=90,\n",
    "                                            wedgeprops=dict(width=0.4),\n",
    "                                            textprops={'fontsize': 10})\n",
    "axes[1, 0].set_title('环形图(Donut Chart)', fontsize=13, fontweight='bold')\n",
    "# 在中心添加文字\n",
    "axes[1, 0].text(0, 0, f'总市场\\n100%', ha='center', va='center', fontsize=14, fontweight='bold')\n",
    "\n",
    "# 4. 图例外置饼图\n",
    "axes[1, 1].pie(market_share, autopct='%1.1f%%', colors=colors_pie, startangle=90,\n",
    "               textprops={'fontsize': 10})\n",
    "axes[1, 1].set_title('图例外置饼图', fontsize=13, fontweight='bold')\n",
    "axes[1, 1].legend(products, loc='center left', bbox_to_anchor=(1, 0, 0.5, 1), fontsize=10)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "print(\"\\n📝 饼图使用场景:\")\n",
    "print(\"  ✓ 展示各部分占总体的比例\")\n",
    "print(\"  ✓ 强调某一部分的重要性\")\n",
    "print(\"  ✓ 市场份额、预算分配等\")\n",
    "print(\"\\n⚠️ 饼图的缺点和注意事项:\")\n",
    "print(\"  ❌ 分类不宜过多(≤5-6个)\")\n",
    "print(\"  ❌ 难以精确比较相近的值\")\n",
    "print(\"  ❌ 不能展示趋势变化\")\n",
    "print(\"  ❌ 多个饼图难以对比\")\n",
    "print(\"  ✅ 建议:分类多时用柱状图代替\")\n",
    "print(\"  ✅ 建议:需要精确对比时用柱状图\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.4 关系类图表\n",
    "\n",
    "#### 3.4.1 散点图(Scatter Plot) - 变量关系"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 生成相关数据\n",
    "np.random.seed(42)\n",
    "n = 200\n",
    "x = np.random.uniform(20, 80, n)\n",
    "y = 2 * x + 10 + np.random.normal(0, 15, n)  # 正相关\n",
    "z = 150 - 1.5 * x + np.random.normal(0, 10, n)  # 负相关\n",
    "category = np.random.choice(['A', 'B', 'C'], n)\n",
    "sizes = np.random.uniform(50, 500, n)\n",
    "\n",
    "print(\"\\n\" + \"=\"*100)\n",
    "print(\"📍 散点图(Scatter Plot) - 展示变量关系\")\n",
    "print(\"=\"*100)\n",
    "\n",
    "fig, axes = plt.subplots(2, 2, figsize=(15, 12))\n",
    "\n",
    "# 1. 基础散点图\n",
    "axes[0, 0].scatter(x, y, alpha=0.6, s=50, color='steelblue', edgecolors='black', linewidth=0.5)\n",
    "# 添加趋势线\n",
    "z_fit = np.polyfit(x, y, 1)\n",
    "p = np.poly1d(z_fit)\n",
    "axes[0, 0].plot(x, p(x), \"r--\", linewidth=2, label=f'趋势线: y={z_fit[0]:.2f}x+{z_fit[1]:.2f}')\n",
    "axes[0, 0].set_title('基础散点图 + 趋势线', fontsize=13, fontweight='bold')\n",
    "axes[0, 0].set_xlabel('X变量', fontsize=11)\n",
    "axes[0, 0].set_ylabel('Y变量', fontsize=11)\n",
    "axes[0, 0].legend(fontsize=10)\n",
    "axes[0, 0].grid(True, alpha=0.3)\n",
    "# 添加相关系数\n",
    "corr = np.corrcoef(x, y)[0, 1]\n",
    "axes[0, 0].text(0.05, 0.95, f'相关系数 r={corr:.3f}', transform=axes[0, 0].transAxes,\n",
    "                fontsize=11, verticalalignment='top',\n",
    "                bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))\n",
    "\n",
    "# 2. 分类散点图\n",
    "for cat, color in zip(['A', 'B', 'C'], ['red', 'blue', 'green']):\n",
    "    mask = category == cat\n",
    "    axes[0, 1].scatter(x[mask], y[mask], alpha=0.6, s=50, color=color, label=f'类别{cat}',\n",
    "                       edgecolors='black', linewidth=0.5)\n",
    "axes[0, 1].set_title('分类散点图', fontsize=13, fontweight='bold')\n",
    "axes[0, 1].set_xlabel('X变量', fontsize=11)\n",
    "axes[0, 1].set_ylabel('Y变量', fontsize=11)\n",
    "axes[0, 1].legend(fontsize=10)\n",
    "axes[0, 1].grid(True, alpha=0.3)\n",
    "\n",
    "# 3. 气泡图(Bubble Chart) - 三维信息\n",
    "scatter = axes[1, 0].scatter(x, y, s=sizes, c=sizes, cmap='viridis', alpha=0.6,\n",
    "                              edgecolors='black', linewidth=0.5)\n",
    "axes[1, 0].set_title('气泡图(大小编码第三维度)', fontsize=13, fontweight='bold')\n",
    "axes[1, 0].set_xlabel('广告投入', fontsize=11)\n",
    "axes[1, 0].set_ylabel('销售额', fontsize=11)\n",
    "cbar = plt.colorbar(scatter, ax=axes[1, 0])\n",
    "cbar.set_label('客户满意度', fontsize=10)\n",
    "axes[1, 0].grid(True, alpha=0.3)\n",
    "\n",
    "# 4. 正负相关对比\n",
    "axes[1, 1].scatter(x, y, alpha=0.5, s=40, color='blue', label='正相关')\n",
    "axes[1, 1].scatter(x, z, alpha=0.5, s=40, color='red', label='负相关')\n",
    "axes[1, 1].set_title('正负相关对比', fontsize=13, fontweight='bold')\n",
    "axes[1, 1].set_xlabel('X变量', fontsize=11)\n",
    "axes[1, 1].set_ylabel('Y变量', fontsize=11)\n",
    "axes[1, 1].legend(fontsize=10)\n",
    "axes[1, 1].grid(True, alpha=0.3)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "print(\"\\n📝 散点图使用场景:\")\n",
    "print(\"  ✓ 探索两个变量间的关系\")\n",
    "print(\"  ✓ 识别相关性(正相关/负相关/无关)\")\n",
    "print(\"  ✓ 发现异常点\")\n",
    "print(\"  ✓ 气泡图可展示三维信息\")\n",
    "print(\"\\n⚠️ 注意事项:\")\n",
    "print(\"  - 数据点过多时注意透明度(alpha)\")\n",
    "print(\"  - 数据点很多时可用hexbin或2D直方图代替\")\n",
    "print(\"  - 相关性≠因果性\")\n",
    "print(\"  - 添加趋势线帮助理解关系\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.4.2 热力图(Heatmap) - 矩阵关系"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 生成相关系数矩阵数据\n",
    "np.random.seed(42)\n",
    "data = pd.DataFrame({\n",
    "    '销售额': np.random.normal(1000, 200, 100),\n",
    "    '广告投入': np.random.normal(50, 10, 100),\n",
    "    '客户数': np.random.normal(100, 20, 100),\n",
    "    '客单价': np.random.normal(200, 40, 100),\n",
    "    '满意度': np.random.normal(4.5, 0.5, 100)\n",
    "})\n",
    "# 添加一些相关性\n",
    "data['销售额'] = data['广告投入'] * 15 + data['客户数'] * 8 + np.random.normal(0, 100, 100)\n",
    "data['客单价'] = data['满意度'] * 40 + np.random.normal(0, 20, 100)\n",
    "\n",
    "corr_matrix = data.corr()\n",
    "\n",
    "print(\"\\n\" + \"=\"*100)\n",
    "print(\"🔥 热力图(Heatmap) - 矩阵数据可视化\")\n",
    "print(\"=\"*100)\n",
    "\n",
    "fig, axes = plt.subplots(2, 2, figsize=(16, 14))\n",
    "\n",
    "# 1. 基础热力图\n",
    "sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='coolwarm', center=0,\n",
    "            square=True, linewidths=1, cbar_kws={'label': '相关系数'},\n",
    "            vmin=-1, vmax=1, ax=axes[0, 0])\n",
    "axes[0, 0].set_title('相关系数热力图(基础)', fontsize=13, fontweight='bold')\n",
    "\n",
    "# 2. 只显示上三角\n",
    "mask = np.triu(np.ones_like(corr_matrix, dtype=bool))\n",
    "sns.heatmap(corr_matrix, mask=mask, annot=True, fmt='.2f', cmap='RdYlGn', center=0,\n",
    "            square=True, linewidths=1, cbar_kws={'label': '相关系数'},\n",
    "            vmin=-1, vmax=1, ax=axes[0, 1])\n",
    "axes[0, 1].set_title('相关系数热力图(上三角)', fontsize=13, fontweight='bold')\n",
    "\n",
    "# 3. 分组数据热力图\n",
    "months = ['1月', '2月', '3月', '4月', '5月', '6月']\n",
    "products = ['产品A', '产品B', '产品C', '产品D', '产品E']\n",
    "sales_matrix = np.random.randint(50, 200, (len(products), len(months)))\n",
    "sales_df = pd.DataFrame(sales_matrix, index=products, columns=months)\n",
    "\n",
    "sns.heatmap(sales_df, annot=True, fmt='d', cmap='YlOrRd',\n",
    "            linewidths=1, cbar_kws={'label': '销售额(万元)'},\n",
    "            ax=axes[1, 0])\n",
    "axes[1, 0].set_title('产品销售热力图', fontsize=13, fontweight='bold')\n",
    "axes[1, 0].set_xlabel('月份', fontsize=11)\n",
    "axes[1, 0].set_ylabel('产品', fontsize=11)\n",
    "\n",
    "# 4. 聚类热力图\n",
    "from scipy.cluster.hierarchy import dendrogram, linkage\n",
    "from scipy.spatial.distance import pdist\n",
    "\n",
    "# 使用seaborn的clustermap\n",
    "# 注意:clustermap返回一个ClusterGrid对象,不能直接用axes\n",
    "axes[1, 1].text(0.5, 0.5, '聚类热力图\\n(见下方单独图)', \n",
    "                ha='center', va='center', fontsize=14, transform=axes[1, 1].transAxes)\n",
    "axes[1, 1].axis('off')\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "# 单独绘制聚类热力图\n",
    "print(\"\\n绘制聚类热力图...\")\n",
    "g = sns.clustermap(sales_df, cmap='YlGnBu', annot=True, fmt='d',\n",
    "                   figsize=(10, 8), linewidths=0.5,\n",
    "                   cbar_kws={'label': '销售额(万元)'})\n",
    "g.fig.suptitle('产品销售聚类热力图', fontsize=14, fontweight='bold', y=0.98)\n",
    "plt.show()\n",
    "\n",
    "print(\"\\n📝 热力图使用场景:\")\n",
    "print(\"  ✓ 展示相关系数矩阵\")\n",
    "print(\"  ✓ 二维数据(如时间×类别)\")\n",
    "print(\"  ✓ 发现数据模式和聚类\")\n",
    "print(\"  ✓ 对比多维度数据\")\n",
    "print(\"\\n⚠️ 注意事项:\")\n",
    "print(\"  - 选择合适的配色方案(diverging/sequential)\")\n",
    "print(\"  - 数值标注要清晰(annot=True)\")\n",
    "print(\"  - 格子不宜过多(建议<20×20)\")\n",
    "print(\"  - center参数对diverging colormap很重要\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 四、Seaborn高级可视化\n",
    "\n",
    "Seaborn是基于Matplotlib的高级可视化库,提供更美观和统计导向的图表。\n",
    "\n",
    "### 4.1 Seaborn的优势"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"=\"*100)\n",
    "print(\"🎨 Seaborn vs Matplotlib\")\n",
    "print(\"=\"*100)\n",
    "\n",
    "comparison = pd.DataFrame({\n",
    "    '特性': ['默认样式', '代码简洁度', '统计功能', '主题定制', '适用场景'],\n",
    "    'Matplotlib': ['较朴素', '较长', '需手动', '灵活但复杂', '完全定制化'],\n",
    "    'Seaborn': ['更美观', '简洁', '内置', '简单易用', '快速统计图表']\n",
    "})\n",
    "\n",
    "print(\"\\n\", comparison.to_string(index=False))\n",
    "\n",
    "print(\"\\n💡 使用建议:\")\n",
    "print(\"  - 快速数据探索 → Seaborn\")\n",
    "print(\"  - 统计可视化 → Seaborn\")\n",
    "print(\"  - 精确定制 → Matplotlib\")\n",
    "print(\"  - 复杂布局 → Matplotlib\")\n",
    "print(\"  - 最佳实践: 两者结合使用\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.2 Seaborn主题和调色板"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 演示Seaborn的5种主题风格\n",
    "print(\"\\n\" + \"=\"*100)\n",
    "print(\"🎨 Seaborn五种内置主题\")\n",
    "print(\"=\"*100)\n",
    "\n",
    "styles = ['darkgrid', 'whitegrid', 'dark', 'white', 'ticks']\n",
    "x_demo = np.linspace(0, 10, 100)\n",
    "y_demo = np.sin(x_demo)\n",
    "\n",
    "fig, axes = plt.subplots(2, 3, figsize=(18, 10))\n",
    "axes = axes.flatten()\n",
    "\n",
    "for idx, style in enumerate(styles):\n",
    "    sns.set_style(style)\n",
    "    axes[idx].plot(x_demo, y_demo, linewidth=2)\n",
    "    axes[idx].set_title(f'Style: {style}', fontsize=12, fontweight='bold')\n",
    "    axes[idx].set_xlabel('X')\n",
    "    axes[idx].set_ylabel('Y')\n",
    "\n",
    "# 最后一个展示调色板\n",
    "axes[5].axis('off')\n",
    "palettes = ['deep', 'muted', 'pastel', 'bright', 'dark', 'colorblind']\n",
    "y_pos = 0.9\n",
    "for pal in palettes:\n",
    "    colors = sns.color_palette(pal, 6)\n",
    "    axes[5].text(0.1, y_pos, f'{pal}:', fontsize=10, fontweight='bold')\n",
    "    for i, c in enumerate(colors):\n",
    "        axes[5].add_patch(plt.Rectangle((0.3 + i*0.1, y_pos-0.02), 0.08, 0.03, facecolor=c))\n",
    "    y_pos -= 0.15\n",
    "axes[5].set_title('常用调色板', fontsize=12, fontweight='bold')\n",
    "axes[5].set_xlim(0, 1)\n",
    "axes[5].set_ylim(0, 1)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "# 恢复默认\n",
    "sns.set_style('darkgrid')\n",
    "\n",
    "print(\"\\n📝 主题选择建议:\")\n",
    "print(\"  - darkgrid: 深色网格,默认,适合大多数场景\")\n",
    "print(\"  - whitegrid: 白色网格,干净专业\")\n",
    "print(\"  - dark/white: 无网格,适合简洁展示\")\n",
    "print(\"  - ticks: 带刻度线,学术风格\")\n",
    "print(\"\\n📝 调色板选择:\")\n",
    "print(\"  - deep: 深色,默认\")\n",
    "print(\"  - muted: 柔和,适合报告\")\n",
    "print(\"  - colorblind: 色盲友好,推荐\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.3 Seaborn常用图表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 生成综合示例数据\n",
    "np.random.seed(42)\n",
    "tips_data = pd.DataFrame({\n",
    "    'total_bill': np.random.gamma(2, 10, 200) + 10,\n",
    "    'tip': np.random.gamma(2, 2, 200) + 1,\n",
    "    'sex': np.random.choice(['Male', 'Female'], 200),\n",
    "    'smoker': np.random.choice(['Yes', 'No'], 200, p=[0.3, 0.7]),\n",
    "    'day': np.random.choice(['Fri', 'Sat', 'Sun', 'Thur'], 200),\n",
    "    'time': np.random.choice(['Lunch', 'Dinner'], 200, p=[0.4, 0.6]),\n",
    "    'size': np.random.randint(1, 7, 200)\n",
    "})\n",
    "\n",
    "print(\"\\n\" + \"=\"*100)\n",
    "print(\"📊 Seaborn统计图表示例\")\n",
    "print(\"=\"*100)\n",
    "\n",
    "fig, axes = plt.subplots(2, 3, figsize=(18, 12))\n",
    "\n",
    "# 1. 分类散点图(catplot的swarm)\n",
    "sns.swarmplot(data=tips_data, x='day', y='total_bill', hue='sex', ax=axes[0, 0])\n",
    "axes[0, 0].set_title('Swarm Plot(蜂群图)', fontsize=12, fontweight='bold')\n",
    "axes[0, 0].set_ylabel('Total Bill', fontsize=10)\n",
    "\n",
    "# 2. 小提琴图\n",
    "sns.violinplot(data=tips_data, x='day', y='total_bill', hue='sex', split=True, ax=axes[0, 1])\n",
    "axes[0, 1].set_title('Violin Plot(小提琴图)', fontsize=12, fontweight='bold')\n",
    "axes[0, 1].set_ylabel('Total Bill', fontsize=10)\n",
    "\n",
    "# 3. 点图(Point Plot)\n",
    "sns.pointplot(data=tips_data, x='day', y='total_bill', hue='sex', ax=axes[0, 2])\n",
    "axes[0, 2].set_title('Point Plot(点图)', fontsize=12, fontweight='bold')\n",
    "axes[0, 2].set_ylabel('Total Bill', fontsize=10)\n",
    "\n",
    "# 4. 回归图\n",
    "sns.regplot(data=tips_data, x='total_bill', y='tip', ax=axes[1, 0],\n",
    "            scatter_kws={'alpha': 0.5}, line_kws={'color': 'red'})\n",
    "axes[1, 0].set_title('Regression Plot(回归图)', fontsize=12, fontweight='bold')\n",
    "axes[1, 0].set_xlabel('Total Bill', fontsize=10)\n",
    "axes[1, 0].set_ylabel('Tip', fontsize=10)\n",
    "\n",
    "# 5. 联合分布图的核心部分\n",
    "sns.scatterplot(data=tips_data, x='total_bill', y='tip', hue='time', ax=axes[1, 1])\n",
    "axes[1, 1].set_title('Scatter with Hue', fontsize=12, fontweight='bold')\n",
    "\n",
    "# 6. 计数图\n",
    "sns.countplot(data=tips_data, x='day', hue='sex', ax=axes[1, 2])\n",
    "axes[1, 2].set_title('Count Plot(计数图)', fontsize=12, fontweight='bold')\n",
    "axes[1, 2].set_ylabel('Count', fontsize=10)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "print(\"\\n📝 Seaborn图表特点:\")\n",
    "print(\"  - Swarm Plot: 显示所有数据点,适合小数据集\")\n",
    "print(\"  - Violin Plot: 箱线图+KDE,显示分布形态\")\n",
    "print(\"  - Point Plot: 显示均值和置信区间\")\n",
    "print(\"  - Reg Plot: 自动添加回归线和置信区间\")\n",
    "print(\"  - Count Plot: 自动计数的柱状图\")\n",
    "print(\"\\n💡 Seaborn的hue参数可以轻松添加第三维度\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 五、图表美化技巧\n",
    "\n",
    "### 5.1 颜色搭配"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"=\"*100)\n",
    "print(\"🎨 图表美化:颜色搭配\")\n",
    "print(\"=\"*100)\n",
    "\n",
    "# 演示不同配色方案\n",
    "categories = ['A', 'B', 'C', 'D', 'E']\n",
    "values = [25, 40, 30, 35, 27]\n",
    "\n",
    "fig, axes = plt.subplots(2, 3, figsize=(18, 10))\n",
    "axes = axes.flatten()\n",
    "\n",
    "color_schemes = [\n",
    "    (['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8'], '清新配色'),\n",
    "    (['#264653', '#2A9D8F', '#E9C46A', '#F4A261', '#E76F51'], '专业配色'),\n",
    "    (['#03045E', '#0077B6', '#00B4D8', '#90E0EF', '#CAF0F8'], '蓝色系'),\n",
    "    (['#D00000', '#DC2F02', '#E85D04', '#F48C06', '#FAA307'], '暖色系'),\n",
    "    (sns.color_palette('Set2', 5), 'Seaborn Set2'),\n",
    "    (sns.color_palette('colorblind', 5), '色盲友好')\n",
    "]\n",
    "\n",
    "for idx, (colors, title) in enumerate(color_schemes):\n",
    "    axes[idx].bar(categories, values, color=colors, alpha=0.8, edgecolor='black')\n",
    "    axes[idx].set_title(title, fontsize=12, fontweight='bold')\n",
    "    axes[idx].set_ylim(0, 50)\n",
    "    axes[idx].grid(axis='y', alpha=0.3)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "print(\"\\n📝 配色原则:\")\n",
    "print(\"  1. 对比度: 前景和背景要有足够对比\")\n",
    "print(\"  2. 一致性: 同类数据使用相近颜色\")\n",
    "print(\"  3. 色盲友好: 避免红绿配色\")\n",
    "print(\"  4. 不超过7种颜色(更多会混乱)\")\n",
    "print(\"  5. 重要数据用鲜艳色突出\")\n",
    "print(\"\\n💡 推荐配色工具:\")\n",
    "print(\"  - ColorBrewer: colorbrewer2.org\")\n",
    "print(\"  - Coolors: coolors.co\")\n",
    "print(\"  - Adobe Color: color.adobe.com\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.2 完整的专业图表示例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建一个完整的专业级图表\n",
    "print(\"\\n\" + \"=\"*100)\n",
    "print(\"✨ 专业级图表完整示例\")\n",
    "print(\"=\"*100)\n",
    "\n",
    "# 准备数据\n",
    "months = pd.date_range('2023-01', periods=12, freq='M')\n",
    "product_a = [120, 135, 142, 158, 165, 180, 175, 190, 195, 205, 210, 225]\n",
    "product_b = [100, 110, 115, 125, 130, 140, 145, 155, 160, 170, 175, 185]\n",
    "target = [150] * 12\n",
    "\n",
    "# 创建图表\n",
    "fig, ax = plt.subplots(figsize=(14, 8))\n",
    "\n",
    "# 绘制数据\n",
    "ax.plot(months, product_a, marker='o', linewidth=3, markersize=8, \n",
    "        color='#2E86AB', label='产品A', zorder=3)\n",
    "ax.plot(months, product_b, marker='s', linewidth=3, markersize=8,\n",
    "        color='#A23B72', label='产品B', zorder=3)\n",
    "ax.plot(months, target, linestyle='--', linewidth=2, color='#E63946',\n",
    "        label='目标', alpha=0.7, zorder=2)\n",
    "\n",
    "# 填充区域\n",
    "ax.fill_between(months, product_a, alpha=0.2, color='#2E86AB')\n",
    "ax.fill_between(months, product_b, alpha=0.2, color='#A23B72')\n",
    "\n",
    "# 标题和标签\n",
    "ax.set_title('2023年产品销售业绩分析', fontsize=18, fontweight='bold', pad=20,\n",
    "             loc='left', color='#2C3E50')\n",
    "ax.set_xlabel('月份', fontsize=13, fontweight='bold', color='#2C3E50')\n",
    "ax.set_ylabel('销售额(万元)', fontsize=13, fontweight='bold', color='#2C3E50')\n",
    "\n",
    "# 添加注释\n",
    "max_idx = np.argmax(product_a)\n",
    "ax.annotate(f'最高值\\n{product_a[max_idx]}万', \n",
    "            xy=(months[max_idx], product_a[max_idx]),\n",
    "            xytext=(20, 20), textcoords='offset points',\n",
    "            fontsize=11, fontweight='bold', color='#2E86AB',\n",
    "            bbox=dict(boxstyle='round,pad=0.5', facecolor='white', edgecolor='#2E86AB', linewidth=2),\n",
    "            arrowprops=dict(arrowstyle='->', color='#2E86AB', lw=2))\n",
    "\n",
    "# 美化网格\n",
    "ax.grid(True, linestyle='--', alpha=0.3, color='gray', linewidth=0.5)\n",
    "ax.set_axisbelow(True)\n",
    "\n",
    "# 优化图例\n",
    "legend = ax.legend(fontsize=12, loc='upper left', frameon=True, shadow=True,\n",
    "                   fancybox=True, framealpha=0.9)\n",
    "legend.get_frame().set_facecolor('white')\n",
    "legend.get_frame().set_edgecolor('#2C3E50')\n",
    "\n",
    "# 去除顶部和右侧边框\n",
    "ax.spines['top'].set_visible(False)\n",
    "ax.spines['right'].set_visible(False)\n",
    "ax.spines['left'].set_linewidth(1.5)\n",
    "ax.spines['bottom'].set_linewidth(1.5)\n",
    "ax.spines['left'].set_color('#2C3E50')\n",
    "ax.spines['bottom'].set_color('#2C3E50')\n",
    "\n",
    "# 设置Y轴范围\n",
    "ax.set_ylim([80, 240])\n",
    "\n",
    "# 添加数据标签(只标注几个关键点)\n",
    "for i in [0, 5, 11]:  # 年初、年中、年末\n",
    "    ax.text(months[i], product_a[i] + 5, f'{product_a[i]}',\n",
    "            ha='center', va='bottom', fontsize=9, fontweight='bold', color='#2E86AB')\n",
    "\n",
    "# 添加背景色块突出某个区间\n",
    "ax.axvspan(months[9], months[11], alpha=0.1, color='green', label='Q4冲刺期')\n",
    "\n",
    "# 添加水印\n",
    "ax.text(0.98, 0.02, '数据来源:公司内部系统', \n",
    "        transform=ax.transAxes, fontsize=9, color='gray',\n",
    "        ha='right', va='bottom', alpha=0.7)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "print(\"\\n✅ 专业图表关键要素:\")\n",
    "print(\"  ✓ 清晰的标题(左对齐更专业)\")\n",
    "print(\"  ✓ 明确的坐标轴标签\")\n",
    "print(\"  ✓ 合适的图例位置和样式\")\n",
    "print(\"  ✓ 适度的网格(不抢眼)\")\n",
    "print(\"  ✓ 去除不必要的边框\")\n",
    "print(\"  ✓ 关键点标注\")\n",
    "print(\"  ✓ 数据来源标注\")\n",
    "print(\"  ✓ 协调的配色\")\n",
    "print(\"  ✓ 合理的留白\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 六、可视化常见错误与改进\n",
    "\n",
    "### 6.1 十大常见错误"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"=\"*100)\n",
    "print(\"❌ 数据可视化十大常见错误\")\n",
    "print(\"=\"*100)\n",
    "\n",
    "errors = [\n",
    "    (\"1. 3D饼图\", \"难以准确判断大小,视觉误导\", \"使用2D饼图或柱状图\"),\n",
    "    (\"2. Y轴不从0开始\", \"夸大差异,误导观众\", \"Y轴从0开始(大多数情况)\"),\n",
    "    (\"3. 饼图分类过多\", \"难以比较,信息混乱\", \"≤5-6个分类,或用柱状图\"),\n",
    "    (\"4. 双Y轴\", \"容易操纵视觉,误导\", \"分开画两张图\"),\n",
    "    (\"5. 颜色过多\", \"视觉疲劳,难以分辨\", \"≤7种颜色\"),\n",
    "    (\"6. 图例不清\", \"不知道代表什么\", \"清晰标注,合理位置\"),\n",
    "    (\"7. 字体太小\", \"看不清楚\", \"标题≥14,标签≥10\"),\n",
    "    (\"8. 图表类型不当\", \"用折线图展示类别对比\", \"根据数据类型选图表\"),\n",
    "    (\"9. 过度装饰\", \"图案、阴影、3D效果\", \"简洁为美,去除装饰\"),\n",
    "    (\"10. 缺少标题和单位\", \"不知道看什么\", \"完整的标题、标签、单位\")\n",
    "]\n",
    "\n",
    "print(\"\\n错误示例 → 如何改进:\\n\")\n",
    "for error, problem, solution in errors:\n",
    "    print(f\"❌ {error}\")\n",
    "    print(f\"   问题: {problem}\")\n",
    "    print(f\"   ✅ 改进: {solution}\")\n",
    "    print()\n",
    "\n",
    "print(\"=\"*100)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6.2 错误示例对比"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 演示:Y轴截断的误导效果\n",
    "print(\"\\n\" + \"=\"*100)\n",
    "print(\"📊 示例:Y轴截断的误导效果\")\n",
    "print(\"=\"*100)\n",
    "\n",
    "companies = ['公司A', '公司B', '公司C']\n",
    "revenues = [100, 105, 110]\n",
    "\n",
    "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))\n",
    "\n",
    "# 错误示例:Y轴从95开始\n",
    "ax1.bar(companies, revenues, color='steelblue', alpha=0.8, edgecolor='black')\n",
    "ax1.set_ylim([95, 115])  # 截断Y轴\n",
    "ax1.set_title('❌ 错误:Y轴截断(夸大差异)', fontsize=13, fontweight='bold', color='red')\n",
    "ax1.set_ylabel('营收(亿元)', fontsize=11)\n",
    "ax1.grid(axis='y', alpha=0.3)\n",
    "for i, v in enumerate(revenues):\n",
    "    ax1.text(i, v + 0.5, str(v), ha='center', fontsize=10)\n",
    "\n",
    "# 正确示例:Y轴从0开始\n",
    "ax2.bar(companies, revenues, color='lightgreen', alpha=0.8, edgecolor='black')\n",
    "ax2.set_ylim([0, 120])\n",
    "ax2.set_title('✅ 正确:Y轴从0开始(真实差异)', fontsize=13, fontweight='bold', color='green')\n",
    "ax2.set_ylabel('营收(亿元)', fontsize=11)\n",
    "ax2.grid(axis='y', alpha=0.3)\n",
    "for i, v in enumerate(revenues):\n",
    "    ax2.text(i, v + 2, str(v), ha='center', fontsize=10)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "print(\"\\n💡 说明:\")\n",
    "print(\"  左图:Y轴从95开始,视觉上公司C比公司A高很多\")\n",
    "print(\"  右图:Y轴从0开始,显示真实差异只有10%\")\n",
    "print(\"  ⚠️ 特例:股票价格、温度等可以不从0开始\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 七、课程总结\n",
    "\n",
    "### 核心知识点\n",
    "\n",
    "1. **可视化六大原则**\n",
    "   - 简洁性、准确性、清晰性、一致性、聚焦性、美观性\n",
    "\n",
    "2. **图表选择决策树**\n",
    "   - 对比 → 柱状图/折线图\n",
    "   - 分布 → 直方图/箱线图\n",
    "   - 组成 → 饼图/堆叠图\n",
    "   - 关系 → 散点图/热力图\n",
    "   - 趋势 → 折线图/面积图\n",
    "\n",
    "3. **Matplotlib核心**\n",
    "   - Figure/Axes架构\n",
    "   - 两种绘图风格(pyplot/面向对象)\n",
    "   - 图表美化技巧\n",
    "\n",
    "4. **Seaborn优势**\n",
    "   - 更美观的默认样式\n",
    "   - 内置统计功能\n",
    "   - 简洁的代码\n",
    "\n",
    "5. **关键技巧**\n",
    "   ```python\n",
    "   # 创建图表\n",
    "   fig, ax = plt.subplots(figsize=(12, 6))\n",
    "   \n",
    "   # 绘图\n",
    "   ax.plot(x, y, label='数据')\n",
    "   \n",
    "   # 美化\n",
    "   ax.set_title('标题', fontsize=14, fontweight='bold')\n",
    "   ax.set_xlabel('X轴')\n",
    "   ax.set_ylabel('Y轴')\n",
    "   ax.legend()\n",
    "   ax.grid(True, alpha=0.3)\n",
    "   ax.spines['top'].set_visible(False)\n",
    "   ax.spines['right'].set_visible(False)\n",
    "   \n",
    "   plt.tight_layout()\n",
    "   plt.show()\n",
    "   ```\n",
    "\n",
    "### 最佳实践\n",
    "\n",
    "1. **数据优先**: 让数据说话,不要过度装饰\n",
    "2. **受众导向**: 考虑观众的专业程度\n",
    "3. **一图一主题**: 不要在一张图里塞太多信息\n",
    "4. **迭代优化**: 多次调整直到满意\n",
    "5. **征求反馈**: 让别人看看是否清晰\n",
    "\n",
    "### 进阶方向\n",
    "\n",
    "- 交互式可视化(Plotly、Bokeh)\n",
    "- 地理可视化(GeoPandas、Folium)\n",
    "- 网络图(NetworkX)\n",
    "- 动画(Matplotlib Animation)\n",
    "- 仪表板(Streamlit、Dash)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 八、课后作业\n",
    "\n",
    "### 作业1:图表重绘(基础)\n",
    "\n",
    "给定数据,绘制以下图表:\n",
    "1. 柱状图:展示5个地区的销售额\n",
    "2. 折线图:展示12个月的趋势\n",
    "3. 饼图:展示产品占比\n",
    "4. 散点图:展示广告投入与销售额关系\n",
    "\n",
    "要求:\n",
    "- 使用专业配色\n",
    "- 添加完整的标题、标签、图例\n",
    "- 添加数据标签\n",
    "- 美化网格和边框"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 作业1数据\n",
    "homework1_data = {\n",
    "    '地区销售': {'华东': 280, '华南': 245, '华北': 215, '西南': 180, '东北': 120},\n",
    "    '月度趋势': {\n",
    "        '月份': ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],\n",
    "        '销售额': [120, 135, 142, 158, 165, 180, 175, 190, 195, 205, 210, 225]\n",
    "    },\n",
    "    '产品占比': {'产品A': 35, '产品B': 28, '产品C': 22, '产品D': 15},\n",
    "    '广告效果': {\n",
    "        '广告投入': [10, 15, 20, 25, 30, 35, 40, 45, 50],\n",
    "        '销售额': [120, 145, 165, 180, 210, 225, 250, 270, 290]\n",
    "    }\n",
    "}\n",
    "\n",
    "print(\"作业1数据已准备好,请开始绘图!\")\n",
    "\n",
    "# TODO: 在此完成作业1\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 作业2:Seaborn统计图表(进阶)\n",
    "\n",
    "使用Seaborn绘制:\n",
    "1. 箱线图:对比不同类别的数据分布\n",
    "2. 小提琴图:展示分布形态\n",
    "3. 热力图:展示相关系数矩阵\n",
    "4. 回归图:展示两变量关系\n",
    "\n",
    "要求:\n",
    "- 使用Seaborn内置样式\n",
    "- 尝试不同的调色板\n",
    "- 添加统计信息(均值线、置信区间等)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 作业2数据\n",
    "np.random.seed(42)\n",
    "homework2_data = pd.DataFrame({\n",
    "    '销售额': np.random.gamma(2, 500, 300) + 500,\n",
    "    '广告投入': np.random.normal(50, 15, 300),\n",
    "    '客户数': np.random.poisson(100, 300),\n",
    "    '满意度': np.random.normal(4.2, 0.6, 300).clip(1, 5),\n",
    "    '地区': np.random.choice(['华东', '华南', '华北'], 300),\n",
    "    '产品': np.random.choice(['A', 'B', 'C'], 300)\n",
    "})\n",
    "\n",
    "print(\"作业2数据已生成!\")\n",
    "print(homework2_data.head())\n",
    "\n",
    "# TODO: 在此完成作业2\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 作业3:综合数据可视化报告(综合)\n",
    "\n",
    "为某公司创建一份可视化分析报告,包含:\n",
    "1. 销售业绩分析(多图表组合)\n",
    "2. 产品对比分析\n",
    "3. 地区表现分析\n",
    "4. 趋势预测分析\n",
    "\n",
    "要求:\n",
    "- 至少10张图表\n",
    "- 使用subplot创建多图布局\n",
    "- 统一的配色方案和风格\n",
    "- 每张图都有清晰的标题和说明\n",
    "- 添加总结性文字说明\n",
    "- 导出为高清图片(300dpi)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 作业3数据生成\n",
    "np.random.seed(42)\n",
    "dates = pd.date_range('2023-01-01', periods=365, freq='D')\n",
    "\n",
    "homework3_data = pd.DataFrame({\n",
    "    '日期': dates,\n",
    "    '销售额': np.random.gamma(2, 5000, 365) + 10000 + np.arange(365) * 50,\n",
    "    '订单量': np.random.poisson(100, 365) + 50,\n",
    "    '客单价': np.random.normal(200, 30, 365),\n",
    "    '广告投入': np.random.normal(5000, 1000, 365),\n",
    "    '地区': np.random.choice(['华东', '华南', '华北', '西南'], 365),\n",
    "    '产品': np.random.choice(['产品A', '产品B', '产品C'], 365),\n",
    "    '渠道': np.random.choice(['线上', '线下'], 365, p=[0.6, 0.4])\n",
    "})\n",
    "\n",
    "print(\"作业3数据已生成!包含365天的详细销售数据\")\n",
    "print(homework3_data.head())\n",
    "print(f\"\\n数据维度: {homework3_data.shape}\")\n",
    "\n",
    "# TODO: 在此完成作业3\n",
    "# 提示:\n",
    "# 1. 使用fig, axes = plt.subplots(4, 3, figsize=(20, 16))创建布局\n",
    "# 2. 按月/季度聚合数据进行分析\n",
    "# 3. 使用不同图表类型展示不同维度\n",
    "# 4. 最后用plt.savefig('report.png', dpi=300)保存\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## 课程结束\n",
    "\n",
    "**下一讲预告**: 第5阶段_第2讲_交互式可视化工具\n",
    "\n",
    "将学习:\n",
    "- Plotly交互式图表\n",
    "- Streamlit仪表板开发\n",
    "- 数据应用部署\n",
    "- 实时数据可视化\n",
    "\n",
    "---\n",
    "\n",
    "📧 如有疑问,请联系助教\n",
    "\n",
    "✅ 完成作业后,请提交Jupyter Notebook文件和图片"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
